home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / sync / syncLock.c < prev    next >
C/C++ Source or Header  |  1991-05-06  |  27KB  |  1,021 lines

  1. /* 
  2.  * syncLock.c --
  3.  *
  4.  *    These are internal locking routines of the Synchronization module.
  5.  *    These routines are slower but safer versions of the routines (found
  6.  *    in sync.h) to get and release monitor locks, and to wait on
  7.  *    and notify condition variables.
  8.  *
  9.  *    A process is blocked by making it wait on an event.  An event is
  10.  *    just an uninterpreted integer that gets 'signaled' by the routine
  11.  *    Sync_SlowBroadcast.
  12.  *
  13.  * Copyright 1985 Regents of the University of California
  14.  * All rights reserved.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/kernel/sync/RCS/syncLock.c,v 9.9 91/05/06 14:49:44 kupfer Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <sync.h>
  22. #include <sprite.h>
  23. #include <mach.h>
  24. #include <list.h>
  25. #include <syncInt.h>
  26. #include <sched.h>
  27. #include <proc.h>
  28. #include <timer.h>
  29. #include <rpc.h>
  30. #include <bstring.h>
  31.  
  32. /*
  33.  * A counter to record the number of busy wait loops executed
  34.  * while trying to P a semaphore.  This is incremented inside the
  35.  * loop of MASTER_LOCK.
  36.  */
  37. int sync_BusyWaits = 0;
  38.  
  39. /*
  40.  * A counter to record the number of events that had clashes on the hash.
  41.  */
  42.  
  43. int    sync_Collisions = 0;
  44.  
  45. /*
  46.  * The event hash chain.  Process control blocks are placed in a hash
  47.  * chain keyed on the event that the process is waiting on.
  48.  */
  49.  
  50. #define PROC_HASHBUCKETS    63
  51. static List_Links eventChainHeaders[PROC_HASHBUCKETS];
  52.  
  53. /*
  54.  * Instrumentation to record the number of calls to the wakeup routine
  55.  * and to record how many processes were woken up.
  56.  */
  57.  
  58. Sync_Instrument sync_Instrument[MACH_MAX_NUM_PROCESSORS];
  59. Sync_Instrument *sync_InstrumentPtr[MACH_MAX_NUM_PROCESSORS];
  60.  
  61. /*
  62.  * Statistics related to remote waiting.
  63.  */
  64. int syncProcWakeupRaces = 0;
  65.  
  66. /* 
  67.  * Locks held during initialization, when there's no "current process".
  68.  */
  69. static nullProcLocks = 0;
  70.  
  71. static void ProcessWakeup _ARGS_((Proc_ControlBlock *procPtr, int waitToken));
  72. static void CheckUnlock _ARGS_ ((Sync_Lock *lockPtr));
  73.  
  74.  
  75. /*
  76.  *----------------------------------------------------------------------------
  77.  *
  78.  * Sync_Init --
  79.  *
  80.  *    This initializes the event hash chain.  The hash table is
  81.  *    an array of list headers.
  82.  *
  83.  *    Instrumentation variables are also initialized.
  84.  *
  85.  * Results:
  86.  *     None.
  87.  *
  88.  * Side effects:
  89.  *    The hash chain headers are initialized to be dummy list elements
  90.  *
  91.  *----------------------------------------------------------------------------
  92.  */
  93. void
  94. Sync_Init()
  95. {
  96.     register int i;
  97.  
  98.     for (i=0 ; i<PROC_HASHBUCKETS ; i++) {
  99.     List_Init(&eventChainHeaders[i]);
  100.     }
  101.     bzero((Address) sync_Instrument, sizeof(sync_Instrument));
  102.     for (i=0; i < MACH_MAX_NUM_PROCESSORS; i++) {
  103.     sync_InstrumentPtr[i] = &sync_Instrument[i];
  104.     }
  105. }
  106.  
  107.  
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * Sync_GetLock --
  112.  *
  113.  *    This is the kernel version of the Sync_GetLock routine. The user
  114.  *     version is written in assembler, but in the kernel we want to
  115.  *    record locking statistics so we have our own version.
  116.  *
  117.  * Results:
  118.  *    None.
  119.  *
  120.  * Side effects:
  121.  *    The type of the previous lock is added to the array of prior types.
  122.  *    The lock is added to the lock stack in the pcb.
  123.  *
  124.  *----------------------------------------------------------------------
  125.  */
  126.  
  127. ReturnStatus
  128. Sync_GetLock(lockPtr)
  129.    Sync_Lock *lockPtr;
  130. {
  131.     ReturnStatus    status = SUCCESS;
  132.     Proc_ControlBlock    *procPtr;
  133.  
  134.     Sync_LockRegister(lockPtr);
  135.     if (Mach_TestAndSet(&(lockPtr->inUse)) != 0) {
  136.     status = Sync_SlowLock(lockPtr); 
  137.     } else {
  138.     Sync_RecordHit(lockPtr);
  139.     Sync_StoreDbgInfo(lockPtr, FALSE);
  140.     Sync_AddPrior(lockPtr);
  141.     }
  142.  
  143.     procPtr = Proc_GetCurrentProc();
  144.     if (procPtr == (Proc_ControlBlock *)NIL) {
  145.     nullProcLocks++;
  146.     } else {
  147.     procPtr->locksHeld++;
  148.     }
  149.  
  150.     return status;
  151. }
  152.  
  153.  
  154. /*
  155.  *----------------------------------------------------------------------
  156.  *
  157.  *  Sync_Unlock--
  158.  *
  159.  *    The kernel version of the unlock routine. We have a different
  160.  *    version from the user so we can do locking statistics.
  161.  *
  162.  * Results:
  163.  *    None.
  164.  *
  165.  * Side effects:
  166.  *    The lock is removed from the lock stack in the pcb.
  167.  *
  168.  *----------------------------------------------------------------------
  169.  */
  170.  
  171. ReturnStatus
  172. Sync_Unlock(lockPtr)
  173.     Sync_Lock *lockPtr;
  174. {
  175.     ReturnStatus    status = SUCCESS;
  176.  
  177.     CheckUnlock(lockPtr);
  178.  
  179.     lockPtr->inUse = 0;
  180.     SyncDeleteCurrent(lockPtr);
  181.     if (lockPtr->waiting) {
  182.     status = Sync_SlowBroadcast((unsigned int)lockPtr, &lockPtr->waiting);
  183.     }
  184.     return status;
  185. }
  186.  
  187.  
  188. /*
  189.  *----------------------------------------------------------------------------
  190.  *
  191.  * Sync_SlowLock --
  192.  *
  193.  *    Acquire a lock while holding the synchronization master lock.
  194.  *
  195.  *      Inside the critical section the inUse bit is checked.  If we have
  196.  *      to wait the process is put to sleep waiting on an event associated
  197.  *      with the lock.
  198.  *
  199.  * Results:
  200.  *    SUCCESS        is always returned.
  201.  *
  202.  * Side effects:
  203.  *      The lock is acquired when this procedure returns.  The process may
  204.  *      have been put to sleep while waiting for the lock to become
  205.  *      available.
  206.  *
  207.  *----------------------------------------------------------------------------
  208.  */
  209.  
  210. ENTRY ReturnStatus
  211. Sync_SlowLock(lockPtr)
  212.     register    Sync_Lock    *lockPtr;
  213. {
  214.     MASTER_LOCK(sched_MutexPtr);
  215.  
  216. #ifdef spur
  217.     Mach_InstCountStart(0);
  218. #endif
  219.  
  220.     while (Mach_TestAndSet(&(lockPtr->inUse)) != 0) {
  221.     lockPtr->waiting = TRUE;
  222.     /*
  223.      * Check the inUse semaphore again after setting the waiting. A zero 
  224.      * semaphore value means the lock was released after our previous
  225.      * TestAndSet and possibly before we set the waiting flag. This test
  226.      * prevents us from waiting if the Sync_Lock missed our waiting flag.
  227.      */
  228.         if (Mach_TestAndSet(&(lockPtr->inUse)) == 0) {
  229.         break;
  230.     }
  231.     (void) SyncEventWaitInt((unsigned int)lockPtr, FALSE);
  232.     Sync_RecordMiss(lockPtr);
  233. #ifdef spur
  234.     Mach_InstCountEnd(1);
  235. #endif
  236.     MASTER_UNLOCK(sched_MutexPtr);
  237.     MASTER_LOCK(sched_MutexPtr);
  238. #ifdef spur
  239.     Mach_InstCountStart(0);
  240. #endif
  241.     }
  242.     Sync_RecordHit(lockPtr);
  243.     Sync_StoreDbgInfo(lockPtr, FALSE);
  244.     Sync_AddPrior(lockPtr);
  245. #ifdef spur
  246.     Mach_InstCountOff(0);
  247.     if (Mach_InstCountIsOn(1)) {
  248.     panic("About to unlock sched_Mutex with inst count on.\n");
  249.     }
  250. #endif
  251.     MASTER_UNLOCK(sched_MutexPtr);
  252.     return(SUCCESS);
  253. }
  254.  
  255.  
  256. /*
  257.  *----------------------------------------------------------------------------
  258.  *
  259.  * Sync_SlowWait --
  260.  *
  261.  *      Wait on a condition.  The lock is released and the process is blocked
  262.  *      on the event.  A future call to SyncSlowBroadcast will signal the
  263.  *      condition and make this process runnable again.  Before returning
  264.  *    the lock is reaquired.
  265.  *
  266.  *      This can only be called while a lock is held.  This forces our
  267.  *      client to safely check global state while in a monitor.
  268.  *
  269.  * Results:
  270.  *    TRUE if interrupted because of signal, FALSE otherwise.
  271.  *
  272.  * Side effects:
  273.  *      Put the process to sleep and release the monitor lock.  Other
  274.  *      processes waiting on the monitor lock become runnable.
  275.  *
  276.  *----------------------------------------------------------------------------
  277.  */
  278.  
  279. ENTRY Boolean
  280. Sync_SlowWait(conditionPtr, lockPtr, wakeIfSignal)
  281.     Sync_Condition    *conditionPtr;    /* Condition to wait on. */
  282.     register Sync_Lock     *lockPtr;    /* Lock to release. */
  283.     Boolean        wakeIfSignal;    /* TRUE => wake if signal pending. */
  284. {
  285.     Boolean    sigPending;
  286.  
  287.     conditionPtr->waiting = TRUE;
  288.     CheckUnlock(lockPtr);
  289.  
  290.     MASTER_LOCK(sched_MutexPtr);
  291.     /*
  292.      * release the monitor lock and wait on the condition
  293.      */
  294.     lockPtr->inUse = 0;
  295.     lockPtr->waiting = FALSE;
  296.     SyncDeleteCurrent(lockPtr);
  297.     SyncEventWakeupInt((unsigned int)lockPtr);
  298.     sigPending = SyncEventWaitInt((unsigned int) conditionPtr, wakeIfSignal);
  299. #ifdef spur
  300.     Mach_InstCountEnd(1);
  301. #endif
  302.     MASTER_UNLOCK(sched_MutexPtr);
  303.  
  304.     (void) Sync_GetLock(lockPtr);
  305.  
  306.     return(sigPending);
  307. }
  308.  
  309.  
  310. /*
  311.  *----------------------------------------------------------------------------
  312.  *
  313.  * Sync_SlowBroadcast --
  314.  *
  315.  *      Mark all processes waiting on an event as runable.  The flag that
  316.  *      indicates there are waiters is cleared here inside the protected
  317.  *      critical section.  This has "broadcast" semantics because everyone
  318.  *      waiting is made runable.  We don't yet have a mechanism to wake up
  319.  *      just one waiting process.
  320.  *
  321.  * Results:
  322.  *    SUCCESS        is always returned.
  323.  *
  324.  * Side effects:
  325.  *    Make processes waiting on the event runnable.
  326.  *
  327.  *----------------------------------------------------------------------------
  328.  */
  329.  
  330. ENTRY ReturnStatus
  331. Sync_SlowBroadcast(event, waitFlagPtr)
  332.     unsigned int event;
  333.     int *waitFlagPtr;
  334. {
  335.     MASTER_LOCK(sched_MutexPtr);
  336.  
  337.     *waitFlagPtr = FALSE;
  338.     SyncEventWakeupInt(event);
  339. #ifdef spur
  340.     if (Mach_InstCountIsOn(1)) {
  341.     panic("About to unlock sched_Mutex with inst count on.\n");
  342.     }
  343. #endif
  344.  
  345.     MASTER_UNLOCK(sched_MutexPtr);
  346.     return(SUCCESS);
  347. }
  348.  
  349.  
  350. /*
  351.  *----------------------------------------------------------------------------
  352.  *
  353.  * Sync_SlowMasterWait --
  354.  *
  355.  *      Wait on an event.  Like SyncSlowWait except that the lock that
  356.  *    is released is a master lock, not a monitor lock.
  357.  *
  358.  * Results:
  359.  *    TRUE if wake up because of a signal, FALSE otherwise.
  360.  *
  361.  * Side effects:
  362.  *      Put the process to sleep and release the master lock.  Other
  363.  *      processes waiting on the monitor lock become runnable.
  364.  *    
  365.  *
  366.  *----------------------------------------------------------------------------
  367.  */
  368.  
  369. ENTRY Boolean
  370. Sync_SlowMasterWait(event, mutexPtr, wakeIfSignal)
  371.     unsigned int     event;        /* Event to wait on. */
  372.     Sync_Semaphore    *mutexPtr;    /* Mutex to release and reaquire. */
  373.     Boolean         wakeIfSignal;    /* TRUE => wake if signal pending. */
  374. {
  375.     Boolean    sigPending;
  376.  
  377.     MASTER_LOCK(sched_MutexPtr);
  378.  
  379.     /*
  380.      * release the master lock and wait on the condition
  381.      */
  382.     MASTER_UNLOCK(mutexPtr);
  383.  
  384.     sigPending = SyncEventWaitInt(event, wakeIfSignal);
  385.  
  386. #ifdef spur
  387.     Mach_InstCountEnd(1);
  388. #endif
  389.  
  390.     MASTER_UNLOCK(sched_MutexPtr);
  391.     /*
  392.      * re-acquire master lock before proceeding
  393.      */
  394.     MASTER_LOCK(mutexPtr);
  395.  
  396.     return(sigPending);
  397. }
  398.  
  399.  
  400. /*
  401.  *----------------------------------------------------------------------------
  402.  *
  403.  * Sync_UnlockAndSwitch --
  404.  *
  405.  *      Release the monitor lock and then perform a context switch to the
  406.  *    given state.  The monitor lock is reaquired before this routine 
  407.  *    returns.
  408.  *
  409.  * Results:
  410.  *    SUCCESS        is always returned.
  411.  *
  412.  * Side effects:
  413.  *      Context switch the process and release the monitor lock.  Other
  414.  *      processes waiting on the monitor lock become runnable.
  415.  *    
  416.  *----------------------------------------------------------------------------
  417.  */
  418.  
  419. void
  420. Sync_UnlockAndSwitch(lockPtr, state)
  421.     register    Sync_Lock     *lockPtr;
  422.     Proc_State            state;
  423. {
  424.     CheckUnlock(lockPtr);
  425.  
  426.     MASTER_LOCK(sched_MutexPtr);
  427.     /*
  428.      * release the monitor lock and context switch.
  429.      */
  430.     lockPtr->inUse = 0;
  431.     lockPtr->waiting = FALSE;
  432.     SyncDeleteCurrent(lockPtr);
  433.     SyncEventWakeupInt((unsigned int)lockPtr);
  434.     Sched_ContextSwitchInt(state);
  435. #ifdef spur
  436.     Mach_InstCountEnd(1);
  437. #endif
  438.     MASTER_UNLOCK(sched_MutexPtr);
  439. }
  440.  
  441.  
  442. /*
  443.  *----------------------------------------------------------------------------
  444.  *
  445.  * SyncEventWakeupInt --
  446.  *
  447.  *      This looks through the process table for processes waiting on an
  448.  *      event.  For each one it finds it clears its event and marks the
  449.  *      process runnable.  Blocked processes are placed on a hash chain
  450.  *    keyed on the event they are blocked on.  It is this hash chain
  451.  *    that this procedure scans.
  452.  *
  453.  * Results:
  454.  *    None.
  455.  *
  456.  * Side effects:
  457.  *      removes process table entries from their event hash chain and
  458.  *      marks them runnable.
  459.  *
  460.  *----------------------------------------------------------------------------
  461.  */
  462.  
  463. INTERNAL void
  464. SyncEventWakeupInt(event)
  465.     unsigned int event;
  466. {
  467.     register    Proc_ControlBlock     *procPtr;
  468.     register    Proc_PCBLink         *hashChainItemPtr;
  469.     register    List_Links         *chainHeader;
  470.     register    List_Links        *itemPtr;
  471.     int        pnum;
  472.  
  473.     if (!sched_MutexPtr->value) {
  474.     panic("SyncEventWakeupInt: master lock not held.\n");
  475.     }
  476.     pnum = Mach_GetProcessorNumber();
  477.     
  478.     sync_Instrument[pnum].numWakeupCalls++;
  479.     chainHeader = &eventChainHeaders[event % PROC_HASHBUCKETS];
  480.  
  481.     itemPtr = List_First(chainHeader);
  482.     while (!List_IsAtEnd(chainHeader, itemPtr)) {
  483.     hashChainItemPtr = (Proc_PCBLink *)itemPtr;
  484.     itemPtr = List_Next(itemPtr);
  485.     procPtr = hashChainItemPtr->procPtr;
  486.     if (procPtr->event != event) {
  487.         sync_Collisions++;
  488.         continue;
  489.     }
  490.     switch (procPtr->state) {
  491.         case PROC_WAITING:
  492.             break;
  493.         case PROC_MIGRATED:
  494.         /*
  495.          * Need to handle waking up migrated processes.
  496.          */
  497.         panic("Can't handle waking up a migrated proc.\n");
  498.         break;
  499.         default:
  500.         panic("%s %s",  
  501.               "Sync_EventWakeupInt:",
  502.               "Tried to wakeup a non-waiting proc.\n");
  503.         break;
  504.  
  505.     }
  506.  
  507.     sync_Instrument[pnum].numWakeups++;
  508.     List_Remove((List_Links *) hashChainItemPtr);
  509.     procPtr->event = NIL;
  510.     if (procPtr->state == PROC_WAITING) {
  511.         procPtr->state = PROC_READY;
  512.         Sched_InsertInQueue(procPtr, (Proc_ControlBlock **) NIL);
  513.     }
  514.     }
  515. }
  516.  
  517.  
  518. /*
  519.  *----------------------------------------------------------------------------
  520.  *
  521.  * Sync_WakeWaitingProcess --
  522.  *
  523.  *      Wake up a particular process as though the local or remote event it is 
  524.  *    awaiting has occurred.
  525.  *
  526.  *    This code was originally written for a uniprocessor. As a result, the
  527.  *    case of signaling a running process was never dealt with. We must
  528.  *    prevent a running process from going to sleep in between the time
  529.  *    we see it is running, and the time it gets the signal. It would seem
  530.  *    we could do this by locking the pcb, but unfortunately 
  531.  *    Sync_EventWaitInt does not grab this lock. This means we have to grab
  532.  *    the sched_MutexPtr. Ideally we would grab the mutex in the sig module
  533.  *    (Sig_Send perhaps). If we did that, then we would deadlock in this
  534.  *    routine. The bottom line is that this routine must do more than its
  535.  *    name implies, due to some weirdness in the way the system is
  536.  *    structured. If a process is ready, nothing is done. If a process
  537.  *    is running, the other processor is interrupted to force it into the
  538.  *    kernel, at which point it sees the signal.
  539.  *
  540.  * Results:
  541.  *    None.
  542.  *
  543.  * Side effects:
  544.  *      If waiting on an event, removes the given process from its event hash 
  545.  *    chain and makes it runnable. If running, interrupts other processor.
  546.  *
  547.  *----------------------------------------------------------------------------
  548.  */
  549.  
  550. void
  551. Sync_WakeWaitingProcess(procPtr)
  552.     register    Proc_ControlBlock     *procPtr;
  553. {
  554.     MASTER_LOCK(sched_MutexPtr);
  555.     if (procPtr->event != NIL) {
  556.     List_Remove(&procPtr->eventHashChain.links);
  557.     procPtr->event = NIL;
  558.     procPtr->state = PROC_READY;
  559.     Sched_InsertInQueue(procPtr, (Proc_ControlBlock **) NIL);
  560.     } else if (procPtr->state == PROC_WAITING) {
  561.         if (!(procPtr->syncFlags & SYNC_WAIT_REMOTE)) {
  562.         panic("Sync_WakeWaitingProcess: Proc waiting but event and remote wait NIL\n");
  563.         }
  564.         ProcessWakeup(procPtr, procPtr->waitToken);
  565.     } else if (procPtr->state == PROC_RUNNING &&
  566.            procPtr->processor != Mach_GetProcessorNumber()) {
  567.     Mach_CheckSpecialHandling(procPtr->processor);
  568.     }
  569. #ifdef spur
  570.     if (Mach_InstCountIsOn(1)) {
  571.     panic("About to unlock sched_Mutex with inst count on.\n");
  572.     }
  573. #endif
  574.     MASTER_UNLOCK(sched_MutexPtr);
  575. }
  576.  
  577.  
  578. /*
  579.  *----------------------------------------------------------------------------
  580.  *
  581.  * Sync_RemoveWaiter --
  582.  *
  583.  *      Remove a process from any event chain it may be on.
  584.  *    This is distinguished from Sync_WakeWaitingProcess because
  585.  *    it does not place the process in the ready queue.
  586.  *
  587.  * Results:
  588.  *    None.
  589.  *
  590.  * Side effects:
  591.  *    None.
  592.  *
  593.  *----------------------------------------------------------------------------
  594.  */
  595.  
  596. void
  597. Sync_RemoveWaiter(procPtr)
  598.     register    Proc_ControlBlock     *procPtr;
  599. {
  600.     MASTER_LOCK(sched_MutexPtr);
  601.     if (procPtr->event != NIL) {
  602.     List_Remove(&procPtr->eventHashChain.links);
  603.     procPtr->event = NIL;
  604.     } else {
  605.     if (procPtr->state == PROC_WAITING) {
  606.         if (!(procPtr->syncFlags & SYNC_WAIT_REMOTE)) {
  607.         panic("Sync_RemoveWaiter: Proc waiting but event and remote wait NIL\n");
  608.         }
  609.         procPtr->syncFlags |= SYNC_WAIT_COMPLETE;
  610.     }
  611.     }
  612.     MASTER_UNLOCK(sched_MutexPtr);
  613. }
  614.  
  615.  
  616. /*
  617.  *----------------------------------------------------------------------------
  618.  *
  619.  * SyncEventWaitInt --
  620.  *
  621.  *    Make a process sleep waiting for an event.  The blocked process is
  622.  *    placed on a hash chain keyed on the event.  This routine will return
  623.  *    without putting the process to sleep if there is a signal pending
  624.  *    and the proper flag is set in the proc table.
  625.  *
  626.  * Results:
  627.  *    TRUE if woke up because of a signal, FALSE otherwise.
  628.  *
  629.  * Side effects:
  630.  *    The event that the process is waiting for is noted in the process
  631.  *    table.  The process is marked as waiting and a new process
  632.  *    is selected to run.
  633.  *
  634.  *----------------------------------------------------------------------------
  635.  */
  636.  
  637. INTERNAL Boolean
  638. SyncEventWaitInt(event, wakeIfSignal)
  639.     unsigned     int     event;        /* Event to wait on. */
  640.     Boolean        wakeIfSignal;    /* TRUE => wake if signal. */
  641. {
  642.     Proc_ControlBlock *procPtr;
  643.     List_Links *chainHeader;
  644.  
  645.     procPtr = Proc_GetCurrentProc();
  646.  
  647.     if (wakeIfSignal && Sig_Pending(procPtr)) {
  648.     return(TRUE);
  649.     }
  650.  
  651.     chainHeader = &eventChainHeaders[event % PROC_HASHBUCKETS];
  652.     List_Insert(&procPtr->eventHashChain.links, LIST_ATREAR(chainHeader));
  653.  
  654.     procPtr->event = event;
  655.     Sched_ContextSwitchInt(PROC_WAITING);
  656.     return(FALSE);
  657. }
  658.  
  659.  
  660. /*
  661.  *----------------------------------------------------------------------------
  662.  *
  663.  * Sync_GetWaitToken --
  664.  *
  665.  *    Return the process id and increment and return wait token for the 
  666.  *    current process.
  667.  *
  668.  * Results:
  669.  *    process ID and wait token for current process.
  670.  *
  671.  * Side effects:
  672.  *    Wait token incremented.
  673.  *
  674.  *----------------------------------------------------------------------------
  675.  */
  676.  
  677. ENTRY void
  678. Sync_GetWaitToken(pidPtr, tokenPtr)
  679.     Proc_PID    *pidPtr;    /* If non-nil pid of current process. */
  680.     int        *tokenPtr;    /* Wait token of current process. */
  681. {
  682.     register    Proc_ControlBlock    *procPtr;
  683.  
  684.     procPtr = Proc_GetCurrentProc();
  685.  
  686.     MASTER_LOCK(sched_MutexPtr);
  687.  
  688.     procPtr->waitToken++;
  689.     if (pidPtr != (Proc_PID *) NIL) {
  690.     *pidPtr = procPtr->processID;
  691.     }
  692.     *tokenPtr = procPtr->waitToken;
  693.  
  694.     MASTER_UNLOCK(sched_MutexPtr);
  695. }
  696.  
  697.  
  698. /*
  699.  *----------------------------------------------------------------------------
  700.  *
  701.  * Sync_SetWaitToken --
  702.  *
  703.  *    Set the wait token for the given process.  Only exists for process
  704.  *    migration should not be used in general.
  705.  *
  706.  * Results:
  707.  *    None.
  708.  *
  709.  * Side effects:
  710.  *    Wait token value set in the PCB for the given process.
  711.  *
  712.  *----------------------------------------------------------------------------
  713.  */
  714.  
  715. ENTRY void
  716. Sync_SetWaitToken(procPtr, waitToken)
  717.     Proc_ControlBlock    *procPtr;    /* Process to set token for. */
  718.     int            waitToken;    /* Token value. */
  719. {
  720.     MASTER_LOCK(sched_MutexPtr);
  721.  
  722.     procPtr->waitToken = waitToken;
  723.  
  724.     MASTER_UNLOCK(sched_MutexPtr);
  725. }
  726.  
  727.  
  728. /*
  729.  *----------------------------------------------------------------------------
  730.  *
  731.  * Sync_ProcWait --
  732.  *
  733.  *    This is called to block a process after it has been told by a
  734.  *    remote host that it has to wait.  The wait completed flag is
  735.  *    checked here to see if the remote host's wakeup message has raced 
  736.  *    (and won) with this process's decision to call this procedure.
  737.  *
  738.  *    For safety, this routine should be expanded to automatically
  739.  *    set up a timeout event which will wake up the process anyway.
  740.  *
  741.  * Results:
  742.  *    TRUE if woke up because of a signal, FALSE otherwise.
  743.  *
  744.  * Side effects:
  745.  *    The wait complete flag of the process is checked and the process
  746.  *    is blocked if a notify message has not already arrived.
  747.  *
  748.  *----------------------------------------------------------------------------
  749.  */
  750.  
  751. ENTRY Boolean
  752. Sync_ProcWait(lockPtr, wakeIfSignal)
  753.     Sync_Lock    *lockPtr;    /* If non-nil release this lock before going to
  754.                  * sleep and reaquire it after waking up. */
  755.     Boolean    wakeIfSignal;    /* TRUE => Don't go to sleep if a signal is
  756.                  *         pending. */
  757. {
  758.     register    Proc_ControlBlock     *procPtr;
  759.     Boolean                releasedLock = FALSE;
  760.     Boolean                sigPending = FALSE;
  761.  
  762.     MASTER_LOCK(sched_MutexPtr);
  763.     procPtr = Proc_GetCurrentProc();
  764.     if (!(procPtr->syncFlags & SYNC_WAIT_COMPLETE)) {
  765.     if (wakeIfSignal && Sig_Pending(procPtr)) {
  766.         /*
  767.          * Check for signals.   If a signal is pending, then bail out.
  768.          */
  769.         sigPending = TRUE;
  770.     } else {
  771.         /*
  772.          * Block the process.  The wakeup message from the remote host
  773.          * has not arrived.
  774.          */
  775.         procPtr->syncFlags |= SYNC_WAIT_REMOTE;
  776.         if (lockPtr != (Sync_Lock *) NIL) {
  777.         /*
  778.          * We were given a monitor lock to release, so release it.
  779.          */
  780.         CheckUnlock(lockPtr);
  781.         lockPtr->inUse = 0;
  782.         lockPtr->waiting = FALSE;
  783.         SyncEventWakeupInt((unsigned int)lockPtr);
  784.         releasedLock = TRUE;
  785.         }
  786.         Sched_ContextSwitchInt(PROC_WAITING);
  787.         if (wakeIfSignal && Sig_Pending(procPtr)) {
  788.         sigPending = TRUE;
  789.         }
  790.     }
  791.     }
  792.     /*
  793.      * After being notified (and context switching back to existence),
  794.      * or if we have already been notified, clear state about the
  795.      * remote wait.  This means our caller should get a new token
  796.      * (ie. retry whatever remote operation it was) before waiting
  797.      * again.
  798.      */
  799.     procPtr->waitToken++;
  800.     procPtr->syncFlags &= ~(SYNC_WAIT_COMPLETE | SYNC_WAIT_REMOTE);
  801. #ifdef spur
  802.     Mach_InstCountEnd(1);
  803. #endif
  804.     MASTER_UNLOCK(sched_MutexPtr);
  805.     if (releasedLock) {
  806.     (void) Sync_GetLock(lockPtr);
  807.     }
  808.     return(sigPending);
  809. }
  810.  
  811.  
  812. /*
  813.  *----------------------------------------------------------------------------
  814.  *
  815.  * Sync_ProcWakeup --
  816.  *
  817.  *    Wakeup a blocked process in response to a message from a remote
  818.  *    host.  Call internal routine to do the work.
  819.  *
  820.  * Results:
  821.  *    None.
  822.  *
  823.  * Side effects:
  824.  *    None.
  825.  *
  826.  *----------------------------------------------------------------------------
  827.  */
  828.  
  829. ENTRY void
  830. Sync_ProcWakeup(pid, token)
  831.     Proc_PID     pid;    /* PID of process to wake up. */
  832.     int        token;    /* Token to use to wake up process. */
  833. {
  834.     Proc_ControlBlock     *procPtr;
  835.  
  836.     procPtr = Proc_GetPCB(pid);
  837.     if (procPtr != (Proc_ControlBlock *)NIL) {
  838.     MASTER_LOCK(sched_MutexPtr);
  839.     ProcessWakeup(procPtr, token);
  840.     MASTER_UNLOCK(sched_MutexPtr);
  841.     }
  842. }
  843.  
  844.  
  845. /*
  846.  *----------------------------------------------------------------------------
  847.  *
  848.  * ProcessWakeup --
  849.  *
  850.  *    Wakeup a blocked process in response to a message from a remote
  851.  *    host.  It is possible that the wakeup message has raced and
  852.  *    won against the local process's call to Sync_ProcWait.  This
  853.  *    protected against with a token and a wakeup complete flag.
  854.  *    (The token provides extra protection against spurious wakeups.
  855.  *     As we don't make any guarantees about the correctness of a
  856.  *     wakeup anyway, we ignore the token here.)
  857.  *
  858.  * Results:
  859.  *    None.
  860.  *
  861.  * Side effects:
  862.  *    syncFlags modified.
  863.  *
  864.  *----------------------------------------------------------------------------
  865.  */
  866.  
  867. /* ARGSUSED */
  868. static INTERNAL void
  869. ProcessWakeup(procPtr, waitToken)
  870.     register    Proc_ControlBlock     *procPtr;    /* Process to wake up.*/
  871.     int                    waitToken;    /* Token to use. Now
  872.                              * this is ignored. */
  873. {
  874.     procPtr->syncFlags |= SYNC_WAIT_COMPLETE;
  875.     if (procPtr->state == PROC_WAITING) {
  876.     /*
  877.      * Only wakeup if are doing a 'process wait' and not an 'event wait'.
  878.      */
  879.     if (procPtr->event == NIL) {
  880.         procPtr->state = PROC_READY;
  881.         Sched_InsertInQueue(procPtr, (Proc_ControlBlock **) NIL);
  882.     }
  883.     } else {
  884.     /*
  885.      * This is a notify message which has raced (and won) with the 
  886.      * process's call to Sync_ProcWait.
  887.      */
  888.     syncProcWakeupRaces++;
  889.     }
  890. }
  891.  
  892.  
  893. /*
  894.  *----------------------------------------------------------------------
  895.  *
  896.  * Sync_RemoteNotify --
  897.  *
  898.  *    Perform an RPC to notify a remote process.
  899.  *
  900.  * Results:
  901.  *    The return code from the RPC.  This enables the caller to decide
  902.  *    if it should wait and retry the notify later if the remote
  903.  *    host is unavailable.
  904.  *
  905.  * Side effects:
  906.  *      This results in a call to Sync_ProcWakeup on the host of the
  907.  *      waiting process.
  908.  *
  909.  *----------------------------------------------------------------------
  910.  */
  911. ReturnStatus
  912. Sync_RemoteNotify(waitPtr)
  913.     Sync_RemoteWaiter *waitPtr;        /* Arguments to remote notify. */
  914. {
  915.     Rpc_Storage storage;
  916.     ReturnStatus status;
  917.  
  918.     storage.requestParamPtr = (Address)waitPtr;
  919.     storage.requestParamSize = sizeof(Sync_RemoteWaiter);
  920.     storage.requestDataSize = 0;
  921.     storage.replyParamSize = 0;
  922.     storage.replyDataSize = 0;
  923.     status = Rpc_Call(waitPtr->hostID, RPC_REMOTE_WAKEUP, &storage);
  924.     return(status);
  925. }
  926.  
  927.  
  928. /*
  929.  *----------------------------------------------------------------------
  930.  *
  931.  * Sync_RemoteNotifyStub --
  932.  *
  933.  *    The service stub for the remote wakeup RPC.
  934.  *
  935.  * Results:
  936.  *    SUCCESS.
  937.  *
  938.  * Side effects:
  939.  *      A call to Sync_ProcWakeup on the process.
  940.  *
  941.  *----------------------------------------------------------------------
  942.  */
  943.  
  944. /* ARGSUSED */
  945. ReturnStatus
  946. Sync_RemoteNotifyStub(srvToken, clientID, command, storagePtr)
  947.     ClientData     srvToken;    /* Handle on server process passed to
  948.                  * Rpc_Reply. */
  949.     int     clientID;    /* Sprite ID of client host (ignored). */
  950.     int     command;    /* Command identifier (ignored). */
  951.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  952.                  * buffers and also indicate the exact amount
  953.                  * of data in the request buffers.  The reply
  954.                  * fields are initialized to NIL for the
  955.                  * pointers and 0 for the lengths.  This can
  956.                  * be passed to Rpc_Reply. */
  957. {
  958.     register Sync_RemoteWaiter *waitPtr;
  959.  
  960.     waitPtr = (Sync_RemoteWaiter *)storagePtr->requestParamPtr;
  961.     Sync_ProcWakeup(waitPtr->pid, waitPtr->waitToken);
  962.     Rpc_Reply(srvToken, SUCCESS, storagePtr, (int (*) ()) NIL,
  963.           (ClientData) NIL);
  964.     return(SUCCESS);
  965. }
  966.  
  967.  
  968. /*
  969.  *----------------------------------------------------------------------
  970.  *
  971.  * CheckUnlock --
  972.  *
  973.  *    Paranoia checks when releasing a monitor or master lock.  Make 
  974.  *    sure that 
  975.  *    (1) the count of obtained locks is high enough
  976.  *    (2) the lock is actually in use
  977.  *    (3) the process that owns the lock is the process that 
  978.  *        releases it .
  979.  *
  980.  * Results:
  981.  *    None.
  982.  *
  983.  * Side effects:
  984.  *    Decrements the counter in the current process's pcb.  If there 
  985.  *    isn't a current process, decrements the global "no process" 
  986.  *    lock counter.
  987.  *
  988.  *----------------------------------------------------------------------
  989.  */
  990.  
  991. static void
  992. CheckUnlock(lockPtr)
  993.     Sync_Lock    *lockPtr;
  994. {
  995.     int            locksHeld; /* 
  996.     int            locksHeld;  * locks held by current process */
  997.     Proc_ControlBlock    *procPtr;
  998.  
  999.     procPtr = Proc_GetCurrentProc();
  1000.     if (procPtr == (Proc_ControlBlock *)NIL) {
  1001.     nullProcLocks--;
  1002.     locksHeld = nullProcLocks;
  1003.     } else {
  1004.     procPtr->locksHeld--;
  1005.     locksHeld = procPtr->locksHeld;
  1006.     }
  1007.     if (locksHeld < 0) {
  1008.     panic("more unlocks than locks.\n");
  1009.     }
  1010.     if (!lockPtr->inUse) {
  1011.     panic("unlocking an unlocked lock.\n");
  1012.     }
  1013.  
  1014. #ifndef CLEAN_LOCK
  1015.     if (lockPtr->holderPCBPtr != (Proc_ControlBlock *)NIL &&
  1016.         lockPtr->holderPCBPtr != procPtr) {
  1017.     panic("unlocking somebody else's lock.\n");
  1018.     }
  1019. #endif
  1020. }
  1021.